package main

import (
	"time"

	"gopkg.in/mgo.v2/bson"
)

type Processor struct {
	cfg         *Config
	dbo         *DBOperation
	connManager *ConnManager
	alarmCall   *AlarmCall

	tGps     int64
	_idAlarm bson.ObjectId
}

func NewProcessor(cfg *Config, dbo *DBOperation, cm *ConnManager, ac *AlarmCall) *Processor {
	p := Processor{cfg: cfg, dbo: dbo, connManager: cm, alarmCall: ac}
	return &p
}

func (p *Processor) Run() {
	p.tGps = p.timeToInt(time.Now())
	if bson.IsObjectIdHex(p.cfg.AlarmId) {
		p._idAlarm = bson.ObjectIdHex(p.cfg.AlarmId)
	}

	go p.processAlarm()
	go p.processDeal()
}

func (p *Processor) timeToInt(t time.Time) int64 {
	y := t.Year() - 2000
	m := int(t.Month())
	d := t.Day()
	h := t.Hour()
	mi := t.Minute()
	s := t.Second()

	ret := int64(s + mi*100 + h*10000 + d*1000000 + m*100000000 + y*10000000000)
	return ret
}

func (p *Processor) processPosition() {
	zLog(nil, "启动读GPS数据协程")
	defer zLog(nil, "读GPS数据协程退出")
	var rid string

	for {
		res := p.dbo.newPosition(p.tGps)
		p.tGps = p.timeToInt(time.Now())
		if len(res) > 0 {
			zLog(nil, "读到", len(res), "条新的GPS数据")
			for _, v := range res {
				rid = v.Rid
				vSend := make(map[string]interface{})
				vSend["action"] = ActionGPS
				vSend["rid"] = rid
				vSend["t"] = v.LL.T

				for conn := range p.connManager.conns {
					if (*conn).HasReceiver(rid) {
						if (*conn).gpsType == GpsBd09 {
							vSend["lat"] = v.LL.LatB
							vSend["lng"] = v.LL.LngB
						} else if (*conn).gpsType == GpsGCJ02 {
							vSend["lat"] = v.LL.LatG
							vSend["lng"] = v.LL.LngG
						} else {

							vSend["lat"] = v.LL.Lat
							vSend["lng"] = v.LL.Lng
						}

						if p.safeSend((*conn).sendChan, vSend) {
							zLog(nil, (*conn).conn.RemoteAddr().String(), "已经关闭")
							(*conn).conn.Close()
							p.connManager.Remove(conn)
						} else {
							zLog(nil, vSend, " 已放入发送chan")
						}
					}
				}
			}
		}
		time.Sleep(time.Second * time.Duration(p.cfg.GpsInterval))
	}
}

type AlarmSendT struct {
	Action   string `json:"action"`
	Id       string `json:"id"`
	Rid      string `json:"rid"`
	Sid      string `json:"sid"`
	Time     int    `json:"t"`
	CardId   int    `json:"cardid"`
	SN       int    `json:"sn"`
	WarnType int    `json:"wt"`
	Level    int    `json:"level"`
}

func (p *AlarmSendT) fromAlarmData(gpsType string, data *AlarmDataT) {
	p.Id = data.Id.Hex()
	p.Rid = data.Rid
	p.Sid = data.Sid
	p.Time = data.Date*1000000 + data.Time
	p.CardId = data.CardId
	p.SN = data.SN
	p.WarnType = data.WarnType
	if p.WarnType == 1 || p.WarnType == 5 {
		p.Level = 0
	} else if p.WarnType == 2 || p.WarnType == 3 || p.WarnType == 4 {
		p.Level = 1
	} else {
		p.Level = 2
	}
}

func (p *Processor) processAlarm() {
	zLog(nil, "启动读报警数据协程")
	defer zLog(nil, "读报警数据协程退出")

	var vSend AlarmSendT
	vSend.Action = ActionAlarm

	for {
		res := p.dbo.newAlarm(p._idAlarm)
		if res != nil {
			zLog(nil, "读到", len(res), "条新的报警数据")
			for _, v := range res {
				if v.WarnType == 6 {

					continue
				}

				if v.WarnType == 1 || v.WarnType == 5 {
					p.alarmCall.callChan <- v
				}

				p._idAlarm = v.Id
				p.cfg.AlarmId = p._idAlarm.Hex()
				for conn := range p.connManager.conns {
					if (*conn).HasReceiver(v.Rid) {
						vSend.fromAlarmData((*conn).gpsType, &v)

						if p.safeSend((*conn).sendChan, vSend) {
							zLog(nil, (*conn).conn.RemoteAddr().String(), "已经关闭")
							(*conn).conn.Close()
							p.connManager.Remove(conn)
						} else {
							zLog(nil, vSend, " 已放入发送chan")
						}
					}
				}
			}
			p.cfg.Save()
		}

		//time.Sleep(time.Second * time.Duration(p.cfg.AlarmInterval))
		time.Sleep(time.Second * time.Duration(1))
	}
}

func (p *Processor) processDeal() {
	zLog(nil, "启动读报警处理数据协程")
	defer zLog(nil, "读报警处理数据协程退出")

	for {
		wids := make([]string, 0)
		res := p.dbo.newAlarmDeal()
		if res != nil {
			zLog(nil, "读到", len(res), "条新的报警处理数据")
			for _, v := range res {
				wids = append(wids, v.Wid)
				for conn := range p.connManager.conns {
					if (*conn).HasReceiver(v.Rid) {
						if p.safeSend((*conn).sendChan, v) {
							zLog(nil, (*conn).conn.RemoteAddr().String(), "已经关闭")
							(*conn).conn.Close()
							p.connManager.Remove(conn)
						} else {
							zLog(nil, v, " 已放入发送chan")
						}
					}
				}
			}
			if len(wids) > 0 {

				p.dbo.setAlarmDealStat(wids, 1)
			}
		}

		time.Sleep(time.Second)
	}
}

func (p *Processor) safeSend(c chan interface{}, v interface{}) (closed bool) {
	defer func() {
		if recover() != nil {
			closed = true
		}
	}()
	c <- v
	return false
}
